package com.chukun.gateway.core.context;

import io.netty.channel.ChannelHandlerContext;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;

/**
 * @author chukun
 * @version 1.0.0
 * @description 抽象的网关上下文实现
 * @createTime 2023/11/19 20:56
 */
public abstract class AbstractContext implements IContext {

    //转发协议，例如http或dubbo等，因为是一开始就决定了，所以加上final
    protected final String protocol;

    //	上下文的状态，因为后面可能涉及到多线程共享，所以加上volatile关键字
    protected volatile int status = IContext.RUNNING;

    protected final ChannelHandlerContext nettyCtx;

    //	保存所有的上下文参数集合
    protected final Map<String, Object> attributes = new HashMap<>();

    //	在请求过程中出现异常则设置异常对象
    protected Throwable throwable;

    /**
     * 是否保持长连接
     */
    protected final boolean keepAlive;

    //	定义是否已经释放请求资源
    protected final AtomicBoolean requestReleased = new AtomicBoolean(false);


    //	存放回调函数的集合
    protected List<Consumer<IContext>> completedCallbacks;

    /**
     * 构造器
     * @param protocol 协议
     * @param nettyCtx netty上下文
     * @param keepAlive 保持连接
     */
    public AbstractContext(String protocol, ChannelHandlerContext nettyCtx, boolean keepAlive) {
        this.protocol = protocol;
        this.nettyCtx = nettyCtx;
        this.keepAlive = keepAlive;
    }

    @Override
    public void runned() {
        this.status = IContext.RUNNING;
    }

    @Override
    public void written() {
        this.status = IContext.WRITTEN;
    }

    @Override
    public void completed() {
        this.status = IContext.COMPLETED;
    }

    @Override
    public void terminated() {
        this.status = IContext.TERMINATED;
    }

    @Override
    public boolean isRunning() {
        return this.status == IContext.RUNNING;
    }

    @Override
    public boolean isWritten() {
        return this.status == IContext.WRITTEN;
    }

    @Override
    public boolean isCompleted() {
        return this.status == IContext.COMPLETED;
    }

    @Override
    public boolean isTerminated() {
        return this.status == IContext.TERMINATED;
    }

    @Override
    public String getProtocol() {
        return protocol;
    }


    @Override
    @SuppressWarnings("unchecked")
    public <T> T getAttribute(String key) {
        return (T) attributes.get(key);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T putAttribute(String key, T value) {
        return (T) attributes.put(key, value);
    }

    @Override
    public void setThrowable(Throwable throwable) {
        this.throwable = throwable;
    }

    @Override
    public Throwable getThrowable() {
        return throwable;
    }

    @Override
    public ChannelHandlerContext getNettyCtx() {
        return nettyCtx;
    }

    @Override
    public boolean isKeepAlive() {
        return keepAlive;
    }

    @Override
    public void addCompletedCallback(Consumer<IContext> consumer) {
        if (completedCallbacks == null) {
            completedCallbacks = new ArrayList<>();
        }
        completedCallbacks.add(consumer);
    }

    @Override
    public void invokeCompletedCallback() {
        if (completedCallbacks != null && !completedCallbacks.isEmpty()) {
            for (Consumer<IContext> callback : completedCallbacks) {
                callback.accept(this);
            }
        }
    }
}
